//Learned：
//1.可以再log.hpp中直接定义一个log对象，这样所有文件下只要包含log.hpp就能 “同步” 日志对象的初始化信息了！
#include <iostream>
#include <string>
#include <stdarg.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;

#define Info 1
#define Warning 2
#define Error 3
#define Fatal 4
#define Debug 5

#define SIZE 1024
#define FILENAME "log.txt"
#define MODE 0666
#define DIRMODE 0777

enum
{
    Screen = 0,
    OneFile,
    VarFile
};

//learning：
//1.时间的接口
//2.格式输出的接口
//3.可变参数
//4.封装成类，重载()


string levelToString(int level)
{
    switch(level)
    {
        case 1:
        return "Info";
        case 2:
        return "Warning";
        case 3:
        return "Error";
        case 4:
        return "Fatal";
        case 5:
        return "Debug";
        default:
        return "None";
    }
}

string timeToString()
{
    time_t t = time(nullptr);
    tm* t_info = localtime(&t);
    string ret;
    ret += to_string(t_info->tm_year+1900) + "-" + to_string(t_info->tm_mon+1) + "-" + to_string(t_info->tm_mday) + " ";
    ret += to_string(t_info->tm_hour) + ":" + to_string(t_info->tm_min) + ":" + to_string(t_info->tm_sec);

    return ret;
}

class Log
{
public:
    Log()
    {
        _printmethod = Screen;
        path = "./log/";
        // if(mkdir(path.c_str(),DIRMODE) < 0)
        // {
        //     perror("mkdir");
        // }
    }

    //提供用户选择打印的方式
    void Enable(int method)
    {
        _printmethod = method;
    }


    //两个参数：既可以可自定义文件名，又可为多文件输出复用（需要自定义文件名）
    void oneFilePrint(const string& logname, const string& logcontents)
    {
        int fd = open(logname.c_str(), O_CREAT|O_WRONLY|O_APPEND, MODE);
        if(fd < 0)
        {
            perror("open");
        }
        write(fd, logcontents.c_str(), logcontents.size());
        close(fd);       
    }

    void varFilePrint(int level, const string& logcontents)
    {
        string logname = path + string(FILENAME) + "." + levelToString(level);
        oneFilePrint(logname,logcontents);
    }


    //[level][time]...
    //分成左右两部分逻辑会清晰一些
    //expected: log(level, "format", "self-defined contents")
    void operator()(int level, const char* format, ...)     
    {
        char leftbuffer[SIZE];
        snprintf(leftbuffer,SIZE,"[%s][%s]",levelToString(level).c_str(), timeToString().c_str());

        char rightbuffer[SIZE];

        va_list s;
        va_start(s,format);
        vsnprintf(rightbuffer,SIZE,format,s);
        
        va_end(s);

        if(_printmethod == OneFile)     //所有日志等级输出到同一个文件
        {
            oneFilePrint(FILENAME,string(leftbuffer) + string(rightbuffer));
        }
        else if(_printmethod == VarFile)    //不同等级输出到不同文件
        {
            varFilePrint(level,string(leftbuffer) + string(rightbuffer));
        }
        else
        {
            printf("%s %s\n",leftbuffer,rightbuffer);
        }
    }

~Log(){};
private:
    int _printmethod;
    string path;

};

Log log;